import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import numpy as np
import logging
import sys
import subprocess
import os
import json

# 假设以下模块是已实现的自定义模块
import image_channels
import image_io
import image_transform
import config
import image_utils as utils

# 配置日志
logging.basicConfig(filename="app.log", level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

class ImageProcessor:
    def __init__(self, master):
        """初始化ImageProcessor类的实例"""
        self.master = master
        self.master.title("Image Processor")  # 默认窗口标题
        self.image = None
        self.image_path = ""
        self.mask_image = None  # 用于存储掩膜图像
        self.current_rect = None  # 初始化 current_rect 属性
        self.language_data = self.load_language_data()
        if self.language_data is None:
            raise ValueError("language_data is not loaded correctly.")
        self.current_language = self.language_data["current_language"]

        self.create_widgets()

    def load_language_data(self):
        """加载语言数据"""
        try:
            with open('language.json', 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            logging.error(f"Failed to load language data: {e}")
            return None

    def create_widgets(self):
        """创建GUI组件"""
        menubar = tk.Menu(self.master)
        self.master.config(menu=menubar)

        file_menu = tk.Menu(menubar)
        file_menu.add_command(label=self.language_data[self.current_language]['open_original'], command=self.open_as_original)
        file_menu.add_command(label=self.language_data[self.current_language]['open_grayscale'], command=self.open_as_gray)
        file_menu.add_command(label=self.language_data[self.current_language]['merge_channels'], command=self.merge_channels)
        file_menu.add_command(label=self.language_data[self.current_language]['save_image'], command=self.save_image)
        file_menu.add_separator()

        language_menu = tk.Menu(file_menu)
        self.language_var = tk.StringVar(value=self.current_language)
        language_menu.add_radiobutton(label="中文", variable=self.language_var, value="zh", command=self.change_language)
        language_menu.add_radiobutton(label="English", variable=self.language_var, value="en", command=self.change_language)
        file_menu.add_cascade(label=self.language_data[self.current_language]['language'], menu=language_menu)
        
        file_menu.add_command(label=self.language_data[self.current_language]['exit'], command=self.master.quit)
        menubar.add_cascade(label=self.language_data[self.current_language]['file'], menu=file_menu)

        info_menu = tk.Menu(menubar)
        info_menu.add_command(label=self.language_data[self.current_language]['details'], command=self.show_image_details)
        menubar.add_cascade(label=self.language_data[self.current_language]['info'], menu=info_menu)

        edit_menu = tk.Menu(menubar)
        edit_menu.add_command(label=self.language_data[self.current_language]['crop'], command=self.crop_image)
        edit_menu.add_command(label=self.language_data[self.current_language]['reset'], command=self.reset_image)
        edit_menu.add_command(label=self.language_data[self.current_language]['brightness_adjustment'], command=self.open_brightness_adjustment)
        edit_menu.add_command(label=self.language_data[self.current_language]['global_thresholding'], command=self.open_global_thresholding)
        menubar.add_cascade(label=self.language_data[self.current_language]['edit'], menu=edit_menu)

        # 分割菜单
        split_menu = tk.Menu(menubar)
        split_menu.add_command(label=self.language_data[self.current_language]['split_channels'], command=self.split_image_channels)
        menubar.add_cascade(label=self.language_data[self.current_language]['split'], menu=split_menu)

        # 边缘菜单
        edge_menu = tk.Menu(menubar)
        edge_menu.add_command(label=self.language_data[self.current_language]['shift_diff'], command=self.open_shift_diff)
        menubar.add_cascade(label=self.language_data[self.current_language]['edge'], menu=edge_menu)

        # 创建掩膜菜单
        mask_menu = tk.Menu(menubar)
        mask_menu.add_command(label=self.language_data[self.current_language]['red_mask'], command=lambda: self.create_mask("red"))
        mask_menu.add_command(label=self.language_data[self.current_language]['green_mask'], command=lambda: self.create_mask("green"))
        mask_menu.add_command(label=self.language_data[self.current_language]['blue_mask'], command=lambda: self.create_mask("blue"))
        menubar.add_cascade(label=self.language_data[self.current_language]['create_mask'], menu=mask_menu)

        # 添加与运算菜单
        bitwise_menu = tk.Menu(menubar)
        bitwise_menu.add_command(label=self.language_data[self.current_language]['bitwise_and'], command=self.apply_bitwise_and)
        bitwise_menu.add_command(label=self.language_data[self.current_language]['bitwise_not'], command=self.apply_bitwise_not)  # 添加非运算功能
        menubar.add_cascade(label=self.language_data[self.current_language]['bitwise'], menu=bitwise_menu)

        self.canvas = tk.Canvas(self.master, width=600, height=400)
        self.canvas.pack()
        self.canvas.bind("<Button-1>", self.on_mouse_down)
        self.canvas.bind("<B1-Motion>", self.on_mouse_move)
        self.canvas.bind("<ButtonRelease-1>", self.on_mouse_up)

    def change_language(self):
        """切换语言"""
        self.current_language = self.language_var.get()
        utils.write_language_data(self.language_data, "current_language", self.current_language)
        logging.info(f"Language changed to {self.current_language}.")
        confirm = messagebox.askyesno(self.language_data[self.current_language]['confirm_restart'], self.language_data[self.current_language]['restart_warning'])
        if confirm:
            self.master.destroy()
            subprocess.Popen([sys.executable] + sys.argv)

    def merge_channels(self):
        """合并多个单通道图像为一个多通道图像"""
        file_paths = filedialog.askopenfilenames()
        if not file_paths:
            return
        if len(file_paths) == 1:
            messagebox.showerror(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['single_file_error'])
            return
        try:
            self.image = image_channels.merge_image_channels(file_paths)
            self.display_image()
        except ValueError as e:
            messagebox.showerror(self.language_data[self.current_language]['error'], str(e))

    def split_image_channels(self):
        """分割当前图像的通道,并在新窗口中显示每个通道"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            return
        if len(self.image.shape) == 2:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['single_channel_error'])
            return
        try:
            channels = image_channels.split_image_channels(self.image)
            for i, channel in enumerate(channels):
                self.display_channel(channel, i)
        except ValueError as e:
            messagebox.showinfo(self.language_data[self.current_language]['error'], str(e))

    def display_channel(self, channel, index):
        """在新窗口中显示单个通道"""
        window = tk.Toplevel(self.master)
        window.title(f"Channel {index}")
        canvas = tk.Canvas(window, width=self.canvas.winfo_width(), height=self.canvas.winfo_height())  # 设置窗口大小为主窗口大小
        canvas.pack()

        def save_channel():
            save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)
            if save_path:
                image_io.save_image(channel, save_path)
                messagebox.showinfo(self.language_data[self.current_language]['success'], self.language_data[self.current_language]['channel_saved'].format(index, save_path))

        save_button = tk.Button(window, text=self.language_data[self.current_language]['save_channel'], command=save_channel)
        save_button.pack()

        # 确保通道图像大小与主窗口图像大小相同
        image = Image.fromarray(channel)
        image = image.resize((self.canvas.winfo_width(), self.canvas.winfo_height()), Image.LANCZOS)
        photo = ImageTk.PhotoImage(image)
        canvas.create_image(0, 0, anchor=tk.NW, image=photo)
        canvas.image = photo

    def open_brightness_adjustment(self):
        """打开亮度调整窗口"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            return

        def adjust_brightness(value):
            factor = int(value) / 100
            adjusted_image = np.clip(self.image * factor, 0, 255).astype(np.uint8)
            self.display_image(adjusted_image)

        brightness_window = tk.Toplevel(self.master)
        brightness_window.title(self.language_data[self.current_language]['brightness_adjustment'])
        brightness_window.geometry("300x100")

        scale = tk.Scale(brightness_window, from_=0, to=200, orient=tk.HORIZONTAL, label=self.language_data[self.current_language]['brightness_label'], command=adjust_brightness)
        scale.set(100)
        scale.pack(fill="x", padx=10, pady=10)

    def open_global_thresholding(self):
        """打开全局阈值处理窗口"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            return

        if len(self.image.shape) != 2:
            messagebox.showerror(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['thresholding_requires_grayscale'])
            return

        # 创建全局阈值窗口
        self.thresholding_window = tk.Toplevel(self.master)
        self.thresholding_window.title(self.language_data[self.current_language]['global_thresholding'])

        # 设置窗口大小与主窗口一致
        self.thresholding_window.geometry(f"{self.master.winfo_width()}x{self.master.winfo_height()}")

        # 添加滑块
        self.scale = tk.Scale(self.thresholding_window, from_=0, to=255, orient=tk.HORIZONTAL, label=self.language_data[self.current_language]['threshold_label'], command=self.update_threshold_image)
        self.scale.set(128)
        self.scale.pack(fill="x", padx=10, pady=10)

        # 添加按钮
        button_frame = tk.Frame(self.thresholding_window)
        button_frame.pack(fill="x", padx=10, pady=10)

        button_apply = tk.Button(button_frame, text=self.language_data[self.current_language].get('apply', 'Apply'), command=self.apply_thresholding)
        button_apply.pack(side=tk.LEFT, padx=5)

        button_cancel = tk.Button(button_frame, text=self.language_data[self.current_language].get('cancel', 'Cancel'), command=self.thresholding_window.destroy)
        button_cancel.pack(side=tk.RIGHT, padx=5)

        # 显示当前图像，大小与主窗口一致
        if self.image is not None:
            pil_image = Image.fromarray(self.image)
            self.display_image_in_window(self.thresholding_window, pil_image)
            self.thresholding_window.image_label = tk.Label(self.thresholding_window)
            self.thresholding_window.image_label.pack()

        # 初始化阈值化图像
        self.update_threshold_image()

    def update_threshold_image(self, event=None):
        """根据滑块值更新图像"""
        threshold = self.scale.get()
        threshold = int(threshold)  # 确保阈值是整数类型

        # 确保图像存在
        if self.image is None:
            logging.error("No image loaded to apply thresholding.")
            return

        # 计算阈值化图像
        gray_image = self.image if len(self.image.shape) == 2 else self.image.mean(axis=2)
        binary_image = (gray_image > threshold).astype(np.uint8) * 255
        pil_image = Image.fromarray(binary_image)

        # 更新显示
        photo = ImageTk.PhotoImage(pil_image)
        if hasattr(self.thresholding_window, 'image_label'):
            self.thresholding_window.image_label.config(image=photo)
            self.thresholding_window.image_label.image = photo  # 保持引用，防止被垃圾回收
        else:
            logging.error("Image label in thresholding window is not initialized.")

    def apply_thresholding(self):
        """应用全局阈值处理"""
        threshold = self.scale.get()
        self.apply_global_thresholding_callback(self.image, threshold)

    def apply_global_thresholding_callback(self, image, threshold):
        """应用全局阈值处理"""
        gray_image = image if len(image.shape) == 2 else image.mean(axis=2)
        binary_image = (gray_image > threshold).astype(np.uint8) * 255
        self.display_image(binary_image, apply=True)

    def display_image_in_window(self, window, pil_image):
        """在指定窗口中显示图像"""
        window.update_idletasks()  # 确保窗口尺寸已更新
        window_width = window.winfo_width()
        window_height = window.winfo_height()
        image_width, image_height = pil_image.size

        if window_width <= 0 or window_height <= 0 or image_width <= 0 or image_height <= 0:
            logging.error("Invalid dimensions for window or image.")
            return
        
        scale = min(window_width / image_width, window_height / image_height)
        new_width = int(image_width * scale)
        new_height = int(image_height * scale)

        if new_width > 0 and new_height > 0:
            resized_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
            photo = ImageTk.PhotoImage(resized_image)
            label = tk.Label(window, image=photo)
            label.image = photo
            label.pack(fill="both", expand=True)
            window.image_label = label  # store the label for later use
        else:
            logging.error("Resized dimensions are not valid.")

    def open_as_original(self):
        """打开原始图像"""
        self.image_path = filedialog.askopenfilename()
        if not self.image_path:
            logging.info("No file selected, operation cancelled.")
            return
        try:
            self.image = image_io.load_image(self.image_path)
            self.display_image()
        except Exception as e:
            logging.error(f"Failed to load image: {e}")
            messagebox.showerror("Error", "Failed to load image.")

    def open_as_gray(self):
        """将原始图像转换为灰度图像"""
        self.image_path = filedialog.askopenfilename()
        if not self.image_path:
            logging.info("No file selected, operation cancelled.")
            return
        try:
            self.image = image_io.load_image(self.image_path, as_gray=True)
            self.display_image()
        except Exception as e:
            logging.error(f"Failed to load image: {e}")
            messagebox.showerror("Error", "Failed to load image.")

    def display_image(self, image=None, apply=False):
        """在主画布上显示当前图像"""
        if image is None:
            image = self.image
        if image is None:
            logging.info("No image to display.")
            return

        pil_image = Image.fromarray(image)
        canvas_width = self.canvas.winfo_width()
        canvas_height = self.canvas.winfo_height()
        if canvas_width == 1 or canvas_height == 1:
            self.master.update_idletasks()
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()

        image_width, image_height = pil_image.size
        scale = min(canvas_width / image_width, canvas_height / image_height)

        if scale < 1:
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            pil_image = pil_image.resize((new_width, new_height), Image.LANCZOS)
        else:
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            pil_image = pil_image.resize((new_width, new_height), Image.BICUBIC)

        photo = ImageTk.PhotoImage(pil_image)
        self.canvas.delete("all")
        x = (canvas_width - new_width) // 2
        y = (canvas_height - new_height) // 2
        self.canvas.create_image(x, y, anchor=tk.NW, image=photo)
        self.canvas.image = photo
        logging.info("Image displayed successfully.")

    def save_image(self):
        """保存当前图像"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_to_be_saved'])
            logging.error("No image to save, save operation cancelled.")
            return

        save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)
        if not save_path:
            logging.info("No save path selected, save operation cancelled.")
            return

        try:
            image_io.save_image(self.image, save_path)
            logging.info(f"Image saved to {save_path}.")
        except Exception as e:
            logging.error(f"Failed to save image: {e}")
            messagebox.showerror("Error", "Failed to save image.")

    def crop_image(self):
        """裁剪当前图像"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_to_be_cropped'])
            logging.error("No image to crop, crop operation cancelled.")
            return

        if not hasattr(self, 'crop_region') or not self.current_rect:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_crop_area'])
            logging.error("No crop area selected, crop operation cancelled.")
            return

        try:
            image_height, image_width = self.image.shape[:2]
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            scale = min(canvas_width / image_width, canvas_height / image_height)
            offset_x = (canvas_width - image_width * scale) // 2
            offset_y = (canvas_height - image_height * scale) // 2

            real_crop_region = (
                int((self.crop_region[0] - offset_y) / scale),
                int((self.crop_region[1] - offset_y) / scale),
                int((self.crop_region[2] - offset_x) / scale),
                int((self.crop_region[3] - offset_x) / scale)
            )

            cropped_image = image_transform.crop_image(self.image, real_crop_region)
            if cropped_image is not None:
                self.image = cropped_image
                self.display_image(apply=True)
                self.canvas.delete(self.current_rect)
                self.current_rect = None
                del self.crop_region
                logging.info("Image cropped successfully.")
            else:
                messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['crop_failed'])
                logging.error("Crop operation failed.")
        except Exception as e:
            logging.error(f"Failed to crop image: {e}")
            messagebox.showerror("Error", "Failed to crop image.")

    def reset_image(self):
        """重置当前图像为原始状态"""
        if not self.image_path:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_reset_image'])
            logging.error("No image to reset, reset operation cancelled.")
            return
        try:
            self.image = image_io.load_image(self.image_path)
            self.display_image(apply=True)
            logging.info("Image reset to original state.")
        except Exception as e:
            logging.error(f"Failed to reset image: {e}")
            messagebox.showerror("Error", "Failed to reset image.")

    def show_image_details(self):
        """显示当前图像的详细信息"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            logging.info("No image loaded, cannot show details.")
            return

        filename = os.path.basename(self.image_path)
        total_pixels = self.image.size
        shape = self.image.shape
        channels = shape[2] if len(shape) == 3 else 1
        dtype = self.image.dtype

        details = self.language_data[self.current_language]['info_str'].format(filename, total_pixels, shape, channels, dtype)
        messagebox.showinfo("INFO", details)
        logging.info("Image details displayed.")

    def on_mouse_down(self, event):
        """处理鼠标左键按下事件"""
        self.rect_start_x = event.x
        self.rect_start_y = event.y
        self.is_drawing = True

    def on_mouse_move(self, event):
        """处理鼠标左键移动事件"""
        if self.is_drawing:
            if self.current_rect:
                self.canvas.delete(self.current_rect)
            self.current_rect = self.canvas.create_rectangle(self.rect_start_x, self.rect_start_y, event.x, event.y, outline="red")

    def on_mouse_up(self, event):
        """处理鼠标左键释放事件"""
        self.rect_end_x = event.x
        self.rect_end_y = event.y
        self.is_drawing = False
        self.crop_region = (min(self.rect_start_y, self.rect_end_y), max(self.rect_start_y, self.rect_end_y),
                              min(self.rect_start_x, self.rect_end_x), max(self.rect_start_x, self.rect_end_x))
        logging.info("Crop region drawn.")

    def open_shift_diff(self):
        """打开移动差分窗口"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            return

        if len(self.image.shape) != 2:
            messagebox.showerror(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['thresholding_requires_grayscale'])
            return

        # 创建移动差分窗口
        self.shift_diff_window = tk.Toplevel(self.master)
        self.shift_diff_window.title(self.language_data[self.current_language]['shift_diff'])

        # 设置窗口大小与主窗口一致
        self.shift_diff_window.geometry(f"{self.master.winfo_width()}x{self.master.winfo_height()}")

        # 添加滑块
        self.shift_scale = tk.Scale(self.shift_diff_window, from_=-3, to=3, orient=tk.HORIZONTAL, label=self.language_data[self.current_language]['shift_label'], command=self.update_shift_diff)
        self.shift_scale.set(0)
        self.shift_scale.pack(fill="x", padx=10, pady=10)

        # 添加按钮
        button_frame = tk.Frame(self.shift_diff_window)
        button_frame.pack(fill="x", padx=10, pady=10)

        button_apply = tk.Button(button_frame, text=self.language_data[self.current_language].get('apply', 'Apply'), command=self.apply_shift_diff)
        button_apply.pack(side=tk.LEFT, padx=5)

        button_cancel = tk.Button(button_frame, text=self.language_data[self.current_language].get('cancel', 'Cancel'), command=self.shift_diff_window.destroy)
        button_cancel.pack(side=tk.RIGHT, padx=5)

        # 显示当前图像，大小与主窗口一致
        if self.image is not None:
            pil_image = Image.fromarray(self.image)
            self.display_image_in_window(self.shift_diff_window, pil_image)
            self.shift_diff_window.image_label = tk.Label(self.shift_diff_window)
            self.shift_diff_window.image_label.pack()

        # 初始化移动差分图像
        self.update_shift_diff()

    def update_shift_diff(self, event=None):
        """根据滑块值更新移动差分图像"""
        shift = self.shift_scale.get()
        shift = int(shift)  # 确保移动量是整数类型

        # 确保图像存在
        if self.image is None:
            logging.error("No image loaded to apply shift diff.")
            return

        # 计算移动差分图像
        shifted_image = np.roll(self.image, shift, axis=0)
        diff_image = np.abs(self.image - shifted_image)
        pil_image = Image.fromarray(diff_image)

        # 更新显示
        photo = ImageTk.PhotoImage(pil_image)
        if hasattr(self.shift_diff_window, 'image_label'):
            self.shift_diff_window.image_label.config(image=photo)
            self.shift_diff_window.image_label.image = photo  # 保持引用，防止被垃圾回收
        else:
            logging.error("Image label in shift diff window is not initialized.")

    def apply_shift_diff(self):
        """应用移动差分处理"""
        shift = self.shift_scale.get()
        self.apply_shift_diff_callback(self.image, shift)

    def apply_shift_diff_callback(self, image, shift):
        """应用移动差分处理"""
        shifted_image = np.roll(image, shift, axis=0)
        diff_image = np.abs(image - shifted_image)
        self.display_image(diff_image, apply=True)

    def create_mask(self, color):
        """创建掩膜，将选定颜色通道的区域变为白色，其他区域变为黑色"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            logging.error("No image loaded to create mask.")
            return

        if len(self.image.shape) != 3:
            messagebox.showerror(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['color_image_required'])
            return

        try:
            # 提取对应颜色通道
            if color == "red":
                mask = self.image[:, :, 0]  # 提取红色通道
            elif color == "green":
                mask = self.image[:, :, 1]  # 提取绿色通道
            elif color == "blue":
                mask = self.image[:, :, 2]  # 提取蓝色通道
            else:
                logging.error(f"Invalid color: {color}")
                return

            # 打印通道值统计信息
            print(f"Mask stats - min: {mask.min()}, max: {mask.max()}, unique: {np.unique(mask)}")

            # 设置阈值并生成二值化掩膜
            threshold = 200  # 可根据需要调整阈值
            binary_mask = np.where(mask > threshold, 255, 0).astype(np.uint8)

            # 将掩膜图像存储为类的属性
            self.mask_image = binary_mask

            # 创建新窗口显示掩膜图像
            self.mask_window = tk.Toplevel(self.master)
            self.mask_window.title(f"{color.capitalize()} Mask")
            self.mask_window.geometry(f"{self.master.winfo_width()}x{self.master.winfo_height()}")

            # 将掩膜图像转换为PIL图像
            pil_image = Image.fromarray(binary_mask)

            # 缩放掩膜图像以匹配主窗口图像的大小
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()
            image_width, image_height = pil_image.size
            scale = min(canvas_width / image_width, canvas_height / image_height)
            new_width = int(image_width * scale)
            new_height = int(image_height * scale)
            resized_image = pil_image.resize((new_width, new_height), Image.LANCZOS)

            photo = ImageTk.PhotoImage(resized_image)

            # 创建画布并显示图像
            canvas = tk.Canvas(self.mask_window, width=new_width, height=new_height)
            canvas.pack()
            canvas.create_image(0, 0, anchor=tk.NW, image=photo)
            canvas.image = photo  # 保持引用，防止被垃圾回收

            # 添加保存按钮
            def save_mask():
                save_path = filedialog.asksaveasfilename(defaultextension=config.DEFAULT_SAVE_FORMAT)
                if save_path:
                    image_io.save_image(binary_mask, save_path)
                    messagebox.showinfo(self.language_data[self.current_language]['success'], self.language_data[self.current_language]['save_mask'])

            save_button = tk.Button(self.mask_window, text=self.language_data[self.current_language]['save_mask'], command=save_mask)
            save_button.pack()
        except Exception as e:
            logging.error(f"Failed to create {color} mask: {e}")
            messagebox.showerror("Error", f"Failed to create {color} mask.")

    def apply_bitwise_and(self):
        """应用与运算（遮罩）"""
        if self.image is None or self.mask_image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            return

        try:
            # 确保掩膜与图像形状一致
            if len(self.image.shape) == 3 and len(self.mask_image.shape) == 2:
                # 如果图像是多通道，而掩膜是单通道，则扩展掩膜
                self.mask_image = np.stack([self.mask_image] * 3, axis=-1)

            if self.image.shape != self.mask_image.shape:
                messagebox.showerror(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['image_mask_mismatch'])
                return

            # 应用与运算
            result_image = np.bitwise_and(self.image, self.mask_image)

            # 显示结果图像
            self.display_image(result_image, apply=True)
        except Exception as e:
            logging.error(f"Failed to apply bitwise AND: {e}")
            messagebox.showerror("Error", "Failed to apply bitwise AND.")

    def apply_bitwise_not(self):
        """应用非运算（反转）"""
        if self.image is None:
            messagebox.showinfo(self.language_data[self.current_language]['error'], self.language_data[self.current_language]['no_image_loaded'])
            return

        try:
            # 应用非运算
            result_image = np.bitwise_not(self.image)

            # 显示结果图像
            self.display_image(result_image, apply=True)
        except Exception as e:
            logging.error(f"Failed to apply bitwise NOT: {e}")
            messagebox.showerror("Error", "Failed to apply bitwise NOT.")

# 创建主窗口和应用程序实例
root = tk.Tk()
app = ImageProcessor(root)
root.mainloop()